#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;

// class A
//{
// public:
//	A() { ++count; };
//	A(const A& t) { ++count; };
//	~A() {};
//		 //静态成员函数，特点：没有this指针
//	static int GetCount()
//	{
//			// 不能访问非静态的了，因为没有this指针
//		//_a;
//		return count;
//	}
//
// private:
//	//类里面声明
//	static int count ;//加了static这个count不是属于某个对象，属于整个类，整个类的所有对象
// }; //但不支持给缺省值，因为缺失值是给初始化列表的，初始化某一个对象，count不属于某一个对象
////类外面定义
// int A::count = 0;
//
// A func()
//{
//	A aa;
//	return aa;
// }
// int main()
//{
//	A aa;
//	//A::count++;//公有的情况下（private放开），可以制定类域访问
//	// 公有
//	// 属于整个类，属于这个类所有对象
//	// 受访问限定符限制
//	//cout<<A::count<<endl;
//	//cout<<aa.count<<endl;
//
//
//	//	// A aa;有名对象
////	//A aa;  //为了调用而创建的，所以要-1
////	//cout << aa.GetCount()-1 << endl;
//
//	//	// A() 这种写法叫做匿名对象，生命周期只在这一行
////	//cout << A().GetCount() - 1 << endl;
//
//	cout << A::GetCount() << endl;
//	// 总结一下：静态成员函数和静态成员变量，本质受限制的全局变量和全局函数
//	// 专属这个类，受类域和访问限定符的限制
//
//	cout << sizeof(A) << endl;//不计算静态的
//
//
//
//	return 0;
//}

// class A
//{
// public:
//	//单参数的构造函数
//	//explicit A(int a)
//	 A(int a)
//		:_a(a)
//	{}
//	int _a = 0;
// };
// class Date
//{
// public:
//	//此处其实也相当于单参数，因为month和day已经初始化了
//	Date(int year, int month = 1, int day = 1)
//		:_year(year)
//		, _month(month)
//		, _day(day)
//	{}
// private:
//	int _year;
//	int _month;
//	int _day;
//
//
// };
// int main()
//{
//	A aa1(1);
//	A aa2(2);
//
//
////内置类型对象 隐式转换成自定义类型对象
////能支持这个转换，是又A的int单参数的构造函数(或支持一个参数多参数带缺省)支持
////如果不想让隐式类型转换发生，构造函数加explicit（但是强制类型转换(显示转换)还是可以的）
//	A aa3 = 3;
//	const A& ra = 3; // 这里引用的是中间产生的临时变量，要加const
//
//	//内置类型， 整型和浮点 隐式互相转
//	int i = 0;
//	double d = i;//会产生临时变量，临时变量具有常性
//	const double& r = i;
//
//	Date d1(2023, 11, 2);
//	Date d2 = (2024, 4, 20);//等价于Date d2 =20; 因为是逗号表达式
//	Date d3 = 2023;///
//
//	//C++11支持下面这样写
//	Date d4 = { 2023,11,2 };
//
//
//	return 0;
//}

//----------------------内部类

// class A
//{
// private:
//	static int k;
//	int h;
// public:
//	//A和B的关系
//	//B就是一个普通的类，只是受A的类域和访问限定符限制
//	class B
//	{
//	public:
//		void foo(const A& a)
//		{
//			cout << k << endl;//OK
//			//B天生就是A的友元
//			cout << a.h << endl;//OK
//		}
//	};
// };
//
////class B // B天生就是A的友元
////{
////public:
////	void foo(const A& a)
////	{
////		cout << k << endl;//OK
////		cout << a.h << endl;//OK
////	}
////};
////class A
////{
////private:
////	static int k;
////	int h;
////	B _b;
////public:
////	   //这种才需要算
////};
//
// int main()
//{
//	cout << sizeof(A) << endl;
//	A aa;
//	A::B bb;
//	return 0;
//}

///////////////////////扩展：拷贝对象时的一些编译器优化（不同编译器结果可能不同）

class A
{
public:
    A(int a = 0) // 构造函数
        : _a(a)
    {
        cout << "A(int a)" << endl;
    }
    A(const A &aa) // 拷贝构造
        : _a(aa._a)
    {
        cout << "A(const A& aa)" << endl;
    }
    A &operator=(const A &aa) // 赋值运算符重载
    {
        cout << "A& operator=(const A& aa)" << endl;
        if (this != &aa)
        {
            _a = aa._a;
        }
        return *this;
    }
    ~A() // 析构函数
    {
        cout << "~A()" << endl;
    }

private:
    int _a;
};
//
//
// int main()
//{
//	//1、先用1构造一个临时对象2、再用临时对象拷贝构造aa1
//	//3、同一个表达式中，连续构造 + 构造 / 构造 + 拷贝构造 / 拷贝构造 + 拷贝构造会合二为一
//	//a、构造 + 构造 - > 构造
//	//b、构造 + 拷贝构造 - > 构造
//	//c、拷贝构造 + 拷贝构造 - > 拷贝构造
//
//	A aa1 = 1;
////1.1被隐式转换为类型 A，然后调用 A(int a) 构造函数构造一个临时对象，该临时对象的 _a 成员被赋值为1。这个步骤会输出 "A(int a)"。
////2.使用这个临时对象拷贝构造一个新的对象 aa1。这个拷贝构造过程调用了 A(const A & aa) 拷贝构造函数，将临时对象的成员变量值复制给 aa1 的成员变量。这个步骤会输出 "A(const A& aa)"。
////3.临时对象超出作用域，调用其析构函数 ~A() 进行清理。
////但其实优化之后只有一个构造
//
//	const A& aa2 = 2;
////2 被隐式转换为类型 A，然后调用 A(int a) 构造函数创建一个临时对象。在这个过程中，控制台输出为 "A(int a)"。
////这个临时对象绑定到 const A & aa2 这个 const 引用上。在绑定引用时不会调用拷贝构造函数。这里的关键是，const 保证了 aa2 引用绑定的对象在引用的作用域内是不可变的。
////在没有 const 的情况下，临时对象的生命周期会延长到 aa2 所在的作用域结束，但在有 const 的情况下，临时对象的生命周期会延长到绑定它的 const 引用所在的作用域结束。
////当 aa2 所在的 main 函数或更大的作用域结束时，临时对象会被销毁，此时调用析构函数 ~A()，控制台输出为 "~A()"。
//
//	return 0;
//}

// void func(A aa1)
//{
//
//
// }
// int main()
//{
//	//构造
//	A aa(1);
//	//拷贝构造(传参)
//	func(aa);
//
//	////构造+拷贝构造->构造
//	//func(A(2));
//
//	////构造+拷贝构造->构造
//	func(3);
////3 被隐式转换为类型 A，调用 A(int a) 构造函数创建一个临时对象。在这个过程中，控制台输出为 "A(int a)"。
////这个临时对象作为参数传递给 func 函数，此时发生拷贝构造。这是因为在函数调用时，参数需要传递给函数内部的形参，而这个传递过程需要创建一个新的对象，即将临时对象复制一份给形参 aa1。这个拷贝构造的过程调用了 A(const A & aa) 拷贝构造函数，将临时对象的成员变量值复制给了形参 aa1 的成员变量。这个步骤会输出 "A(const A& aa)"。
////在 func 函数中，aa1 作为函数的局部变量，在函数结束时会被销毁。因此，在 func 函数结束时，会调用 aa1 的析构函数 ~A() 进行清理。
//
//	return 0;
//}

A func()
{
    A aa;
    return aa;
}
// int main()
//{
//	//拷贝构造+拷贝构造-> 拷贝构造
//	//A aa1 = func();
//
//
//	//不在同一个式子，不会被优化。
//	A aa2;
//	aa2 = func();
//	//在 main 函数中，首先创建了一个名为 aa2 的对象，调用了默认构造函数 A(int a)，输出 "A(int a)"。
//
//	//接着，执行 aa2 = func(); 这一语句。在这个语句中，首先调用了 func() 函数。在 func() 函数内部，又创建了一个局部对象 A aa; ，调用了默认构造函数 A(int a)，输出 "A(int a)"。
//
//	//然后，将局部对象 aa 作为返回值返回给 main 函数。但是在返回之前，编译器会创建一个临时对象来存储返回值，因此会再次调用拷贝构造函数 A(const A & aa)，输出 "A(const A& aa)"。
//
//	//返回的临时对象被赋值给了 aa2，因此调用了赋值运算符重载函数 A & operator=(const A & aa)，输出 "A& operator=(const A& aa)"。
//
//	//在 main 函数结束时，aa2 对象超出了其作用域，所以会调用析构函数 ~A()，输出 "~A()"。
//
//	//同样，返回的临时对象也会超出其作用域，因此也会调用析构函数 ~A()，输出 "~A()"。
////A(int a)    // 构造函数：创建 aa2 对象
////A(int a)    // 构造函数：创建 func() 函数中的局部对象 aa
////A& operator=(const A & aa)    // 赋值运算符重载：将 func() 的返回值赋值给 aa2
////~A()    // 析构函数：销毁 aa2 对象
////~A()    // 析构函数：销毁 func() 的返回值临时对象
//	return 0;
//}

//// 传值传参
// A aa1;
// f1(aa1);
// cout << endl;
//// 传值返回
// f2();
// cout << endl;
//// 隐式类型，连续构造+拷贝构造->优化为直接构造
// f1(1);
//// 一个表达式中，连续构造+拷贝构造->优化为一个构造
// f1(A(2));
// cout << endl;
//// 一个表达式中，连续拷贝构造+拷贝构造->优化一个拷贝构造
// A aa2 = f2();
// cout << endl;
//// 一个表达式中，连续拷贝构造+赋值重载->无法优化
// aa1 = f2();
// cout << endl;

// int main()
//{
//	A aa1(1);//构造
//	A aa2(aa1);//拷贝构造
//	A aa3 = aa1;//这里是拷贝构造，why？用一个已经存在的对象，拷贝初始化另一个要创建的对象
//
//	//两个已经存在的对象拷贝，赋值拷贝
//	aa2 = aa3;//赋值
// }

// 构造 + 拷贝构造->构造
// 拷贝构造+ 拷贝构造->拷贝构造
A func2()
{
    A aa;
    return aa;
}
int main()
{
    A ret1 = func2();
    return 0;
}